package com.vietnam.power.service.impl;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.vietnam.power.constant.AppConfigurationConstant;
import com.vietnam.power.dao.ApplicationDao;
import com.vietnam.power.dao.FileDao;
import com.vietnam.power.domain.FileSearchCriteria;
import com.vietnam.power.domain.FileUpload;
import com.vietnam.power.service.FileService;

@Service
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public class FileServiceImpl implements FileService {

	@Autowired
	private FileDao fileDao;

	@Autowired
	private ApplicationDao applicationDao;

	private List<FileUpload> convertToDomainList(List<com.vietnam.power.persitence.FileUpload> files) {
		List<FileUpload> lst = new ArrayList<FileUpload>();
		for (com.vietnam.power.persitence.FileUpload file : files) {
			lst.add(convertToDomain(file));
		}
		return lst;
	}

	private FileUpload convertToDomain(com.vietnam.power.persitence.FileUpload file) {
		FileUpload fu = new FileUpload();
		fu.convertToDomain(file);
		return fu;
	}

	public FileUpload getFileById(int id) {
		return convertToDomain(fileDao.getFileById(id));
	}

	public List<FileUpload> getFilesByName(String fileName) {
		return convertToDomainList(fileDao.getFilesByName(fileName));
	}

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void deleteFile(int id, String appPath) {
		String fullPathThumb = null;
		String fullPathFull = null;
		// get file path from database
		String filePath = AppConfigurationConstant.FILE_UPLOAD.FILE_UPLOAD_ROOT_FOLDER + File.separator;

		FileUpload fu = getFileById(id);

		if (StringUtils.isNotBlank(fu.getThumbName())) {
			fullPathThumb = appPath + filePath + fu.getThumbName();
		}
		if (StringUtils.isNotBlank(fu.getFileName())) {
			fullPathFull = appPath + filePath + fu.getFileName();
		}

		// delete in database
		fileDao.deleteFile(fileDao.getFileById(id));

		if (fullPathThumb != null) {
			File f = new File(fullPathThumb);
			if (f.exists()) {
				f.delete();
			}
		}

		if (fullPathFull != null) {
			File f = new File(fullPathFull);
			if (f.exists()) {
				f.delete();
			}
		}

	}

	public int createImages(String appPath, byte[] bytes, String fileExt, String fileFor) {
		String filename = "vn-" + System.currentTimeMillis() + "." + fileExt;

		com.vietnam.power.persitence.FileUpload f = new com.vietnam.power.persitence.FileUpload();
		if (StringUtils.equalsIgnoreCase(fileFor, AppConfigurationConstant.FILE_UPLOAD.FILE_PRODUCT_NAME)) {
			f.setName(AppConfigurationConstant.FILE_UPLOAD.FILE_PRODUCT_NAME);
		} else if (StringUtils.equalsIgnoreCase(fileFor, AppConfigurationConstant.FILE_UPLOAD.FILE_ARTICLE_NAME)) {
			f.setName(AppConfigurationConstant.FILE_UPLOAD.FILE_ARTICLE_NAME);
		} else if (StringUtils.equalsIgnoreCase(fileFor, AppConfigurationConstant.FILE_UPLOAD.FILE_BANNER_NAME)) {
			f.setName(AppConfigurationConstant.FILE_UPLOAD.FILE_BANNER_NAME);
		} else if (StringUtils.equalsIgnoreCase(fileFor, AppConfigurationConstant.FILE_UPLOAD.FILE_SLIDER_NAME)) {
			f.setName(AppConfigurationConstant.FILE_UPLOAD.FILE_SLIDER_NAME);
		} else if (StringUtils.equalsIgnoreCase(fileFor, AppConfigurationConstant.FILE_UPLOAD.FILE_ADVERTISING_NAME)) {
			f.setName(AppConfigurationConstant.FILE_UPLOAD.FILE_ADVERTISING_NAME);
		} else if (StringUtils.equalsIgnoreCase(fileFor, AppConfigurationConstant.FILE_UPLOAD.FILE_AVATAR_NAME)) {
			f.setName(AppConfigurationConstant.FILE_UPLOAD.FILE_AVATAR_NAME);
		} else if (StringUtils.equalsIgnoreCase(fileFor, AppConfigurationConstant.FILE_UPLOAD.FILE_FOOTER_NAME)) {
			f.setName(AppConfigurationConstant.FILE_UPLOAD.FILE_FOOTER_NAME);
		}

		f.setStatus(Boolean.FALSE);
		f.setThumbName(AppConfigurationConstant.FILE_UPLOAD.FILE_THUMB + File.separator + filename);
		f.setFileName(AppConfigurationConstant.FILE_UPLOAD.FILE_FULL_SIZE + File.separator + filename);

		fileDao.saveFile(f);
		// create full size image first
		createFile(f.getFileName(), appPath, bytes);
		//
		return f.getId();
	}

	public void createThumbImage(String appPath, int fileId, String thumbFor, int x, int y, int w, int h, int resizew, int resizeh) throws IOException {
		com.vietnam.power.persitence.FileUpload fu = fileDao.getFileById(fileId);

		String filePath = AppConfigurationConstant.FILE_UPLOAD.FILE_UPLOAD_ROOT_FOLDER + File.separator;
		String fullPath = appPath + filePath + fu.getFileName();
		BufferedImage originalImage = ImageIO.read(new File(fullPath));
		int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();

		originalImage = resizeImage(originalImage, type, resizew, resizeh);
		originalImage = cropImage(originalImage, x, y, w, h);

		String fileExt = FilenameUtils.getExtension(fu.getThumbName());

		if (StringUtils.equalsIgnoreCase(thumbFor, AppConfigurationConstant.FILE_UPLOAD.FILE_PRODUCT_NAME)) {
			originalImage = resizeImage(originalImage, type, AppConfigurationConstant.FILE_UPLOAD.PRODUCT_THUMB_WIDTH,
					AppConfigurationConstant.FILE_UPLOAD.PRODUCT_THUMB_HEIGHT);
		} else if (StringUtils.equalsIgnoreCase(thumbFor, AppConfigurationConstant.FILE_UPLOAD.FILE_ARTICLE_NAME)) {
			originalImage = resizeImage(originalImage, type, AppConfigurationConstant.FILE_UPLOAD.ARTICLE_THUMB_WIDTH,
					AppConfigurationConstant.FILE_UPLOAD.ARTICLE_THUMB_HEIGHT);
			// update full size image as thumb
			if (fullPath != null) {
				File f = new File(fullPath);
				ImageIO.write(originalImage, fileExt, f);
			}
		} else if (StringUtils.equalsIgnoreCase(thumbFor, AppConfigurationConstant.FILE_UPLOAD.FILE_BANNER_NAME)) {
			// update full size image as thumb
			BufferedImage originalFileImage = ImageIO.read(new File(fullPath));
			double rate = (double) originalFileImage.getWidth() / resizew;
			originalFileImage = cropImage(originalFileImage, (int)Math.round(x * rate), (int)Math.round(y * rate), (int)Math.round(w * rate), (int)Math.round(h * rate));
			if (fullPath != null) {
				File f = new File(fullPath);
				ImageIO.write(originalFileImage, fileExt, f);
			}
			originalImage = resizeImage(originalImage, type, AppConfigurationConstant.FILE_UPLOAD.BANNER_THUMB_WIDTH,
					AppConfigurationConstant.FILE_UPLOAD.BANNER_THUMB_HEIGHT);
		} else if (StringUtils.equalsIgnoreCase(thumbFor, AppConfigurationConstant.FILE_UPLOAD.FILE_FOOTER_NAME)) {
			// update full size image as thumb
			BufferedImage originalFileImage = ImageIO.read(new File(fullPath));
			double rate = (double) originalFileImage.getWidth() / resizew;
			originalFileImage = cropImage(originalFileImage, (int)Math.round(x * rate), (int)Math.round(y * rate), (int)Math.round(w * rate), (int)Math.round(h * rate));
			if (fullPath != null) {
				File f = new File(fullPath);
				ImageIO.write(originalFileImage, fileExt, f);
			}
			originalImage = resizeImage(originalImage, type, AppConfigurationConstant.FILE_UPLOAD.FOOTER_THUMB_WIDTH,
					AppConfigurationConstant.FILE_UPLOAD.FOOTER_THUMB_HEIGHT);
		} else if (StringUtils.equalsIgnoreCase(thumbFor, AppConfigurationConstant.FILE_UPLOAD.FILE_SLIDER_NAME)) {
			BufferedImage originalFileImage = ImageIO.read(new File(fullPath));
			double rate = (double) originalFileImage.getWidth() / resizew;
			originalFileImage = cropImage(originalFileImage, (int)Math.round(x * rate), (int)Math.round(y * rate), (int)Math.round(w * rate), (int)Math.round(h * rate));
			if (fullPath != null) {
				File f = new File(fullPath);
				ImageIO.write(originalFileImage, fileExt, f);
			}
			originalImage = resizeImage(originalImage, type, AppConfigurationConstant.FILE_UPLOAD.SLIDER_THUMB_WIDTH,
					AppConfigurationConstant.FILE_UPLOAD.SLIDER_THUMB_HEIGHT);
		} else if (StringUtils.equalsIgnoreCase(thumbFor, AppConfigurationConstant.FILE_UPLOAD.FILE_ADVERTISING_NAME)) {
			originalImage = resizeImage(originalImage, type, AppConfigurationConstant.FILE_UPLOAD.ADV_THUMB_WIDTH,
					AppConfigurationConstant.FILE_UPLOAD.ADV_THUMB_HEIGHT);
			// update full size image as thumb
			if (fullPath != null) {
				File f = new File(fullPath);
				ImageIO.write(originalImage, fileExt, f);
			}
		} else if (StringUtils.equalsIgnoreCase(thumbFor, AppConfigurationConstant.FILE_UPLOAD.FILE_AVATAR_NAME)) {
			originalImage = resizeImage(originalImage, type, AppConfigurationConstant.FILE_UPLOAD.AVATAR_THUMB_WIDTH,
					AppConfigurationConstant.FILE_UPLOAD.AVATAR_THUMB_HEIGHT);
			// update full size image as thumb
			if (fullPath != null) {
				File f = new File(fullPath);
				ImageIO.write(originalImage, fileExt, f);
			}
		}

		String fullThumbPath = appPath + filePath + fu.getThumbName();
		File f = new File(fullThumbPath);
		ImageIO.write(originalImage, fileExt, f);
	}

	private void createFile(String filename, String appPath, byte[] bytes) {
		String filePath = AppConfigurationConstant.FILE_UPLOAD.FILE_UPLOAD_ROOT_FOLDER + File.separator;
		String fullPath = appPath + filePath + filename;
		File f = new File(fullPath);
		try {
			FileUtils.writeByteArrayToFile(f, bytes);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	private BufferedImage resizeImage(BufferedImage originalImage, int type, int width, int height) {
		BufferedImage resizedImage = new BufferedImage(width, height, type);
		Graphics2D g = resizedImage.createGraphics();
		g.drawImage(originalImage, 0, 0, width, height, null);
		g.dispose();

		return resizedImage;
	}

	private BufferedImage cropImage(BufferedImage src, int x, int y, int width, int height) {
		BufferedImage dest = src.getSubimage(x, y, width, height);
		return dest;
	}

	public boolean validateFileGroup(String name) {
		long no = fileDao.countFilesInGroup(name);
		if (StringUtils.equalsIgnoreCase(name, AppConfigurationConstant.FILE_UPLOAD.FILE_BANNER_NAME)) {
			int max = applicationDao.getAppConfigurationByName(AppConfigurationConstant.APP_CONFIGURATION.MAX_PICTURES_FOR_BANNER).getThreshold();
			if (no >= max) {
				return false;
			}
		} else if (StringUtils.equalsIgnoreCase(name, AppConfigurationConstant.FILE_UPLOAD.FILE_SLIDER_NAME)) {
			int max = applicationDao.getAppConfigurationByName(AppConfigurationConstant.APP_CONFIGURATION.MAX_PICTURES_FOR_SLIDER).getThreshold();
			if (no >= max) {
				return false;
			}
		} else if (StringUtils.equalsIgnoreCase(name, AppConfigurationConstant.FILE_UPLOAD.FILE_ADVERTISING_NAME)) {
			int max = applicationDao.getAppConfigurationByName(AppConfigurationConstant.APP_CONFIGURATION.MAX_PICTURES_FOR_ADVERTISING).getThreshold();
			if (no >= max) {
				return false;
			}
		}

		return true;
	}

	public void updateFileStatusToActive(int id,String desc) {
		com.vietnam.power.persitence.FileUpload fu = fileDao.getFileById(id);
		fu.setStatus(Boolean.TRUE);
		if (StringUtils.isNotBlank(desc)) {
			fu.setDescription(desc);
		}
		fileDao.updateFile(fu);
	}

	public List<FileUpload> searchFiles(FileSearchCriteria s) {
		return convertToDomainList(fileDao.searchFiles(s));
	}
	
	public List<FileUpload> getUnusedFiles() {
		return convertToDomainList(fileDao.getUnusedFiles());
	}
}
